package com.kalvan.web.thread;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 异步线程任务父类
 *
 * @author chenliang
 */
@Slf4j
public abstract class BaseAsynchronousCmd implements DisposableBean {

    protected ThreadPoolExecutor threadPool;

    protected int corePoolSize;
    protected int maximumPoolSize;
    protected long keepAliveTime;
    protected int workQueueSize;
    /**
     * 最大的量
     */
    protected int maxSize;

    /**
     * 用来实例化线程池的构造函数
     *
     * @param corePoolSize    核心线程数
     * @param maximumPoolSize 线程池维护线程的最大数量
     * @param keepAliveTime   线程池维护线程所允许的空闲时间
     * @param workQueueSize   线程池所使用的缓冲队列数
     */
    public BaseAsynchronousCmd(int corePoolSize, int maximumPoolSize,
                               long keepAliveTime, int workQueueSize) {
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.keepAliveTime = keepAliveTime;
        this.workQueueSize = workQueueSize;
        this.maxSize = maximumPoolSize + workQueueSize;
        threadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                keepAliveTime, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(workQueueSize),
                new ThreadPoolExecutor.CallerRunsPolicy());
        threadPool.allowCoreThreadTimeOut(true);
        // 自定义异常捕获
        threadPool.setThreadFactory(new HandlerThreadFactory());
    }

    /**
     * 当前总线程是否超过线程池范围
     *
     * @return boolean
     */
    protected boolean isOutOfRange() {
        int queueSize = threadPool.getQueue().size();
        int active = threadPool.getActiveCount();
        int poolRunCount = queueSize + active;
        return poolRunCount >= this.maxSize;
    }

    static class HandlerThreadFactory implements ThreadFactory {
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            // 设定线程工厂的异常处理器
            t.setUncaughtExceptionHandler(new UncaughtExceptionHandler());
            return t;
        }
    }

    static class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            log.error("多线程运行异常", e);
        }
    }

    @Override
    public void destroy() {
        log.info("start shutdown thread pool");
        if (threadPool != null) {
            threadPool.shutdown();
        }
        log.info("end shutdown thread pool");
    }

}
